package edu.cmu.cs211.bacon.tests;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;

import java.util.*;

import edu.cmu.cs211.bacon.cable.*;


public class BaconCableCompanyTest {

	@Test
	public void square() throws Exception {
		CableWire wireAB = new CableWire("A: Kevin's house", "B: LA Fitness", 1);
		CableWire wireBA = new CableWire("B: LA Fitness", "A: Kevin's house", 1);
		CableWire wireAC = new CableWire("A: Kevin's house", "C: Movie theater", 4);
		CableWire wireCA = new CableWire("C: Movie theater", "A: Kevin's house", 4);
		CableWire wireCB = new CableWire("C: Movie theater", "B: LA Fitness", 5);
		CableWire wireBC = new CableWire("B: LA Fitness", "C: Movie theater", 5);
		CableWire wireCD = new CableWire("C: Movie theater", "D: Secret hideout", 3);
		CableWire wireDC = new CableWire("D: Secret hideout", "C: Movie theater", 3);

		Set<CableWire> edges = new HashSet<CableWire>();
		edges.add(wireAB);
		edges.add(wireBA);
		edges.add(wireAC);
		edges.add(wireCA);
		edges.add(wireCB);
		edges.add(wireBC);
		edges.add(wireCD);
		edges.add(wireDC);

		Set<CableWire> minBacon = BaconCableCompany.getMst(edges);
		assertTrue("square MST should contain edge 1", 
				minBacon.contains(wireAB) || minBacon.contains(wireBA));
		assertTrue("square MST should contain edge 3", 
				minBacon.contains(wireCD) || minBacon.contains(wireDC));
		assertTrue("square MST should contain edge 4", 
				minBacon.contains(wireAC) || minBacon.contains(wireCA));
		assertTrue("square MST should not contain edge 5",
				!minBacon.contains(wireCB) && !minBacon.contains(wireBC));
	}

	@Test (expected = NullPointerException.class)
	public void empty() throws Exception {
		BaconCableCompany.getMst(null);
	}

	@Test
	public void oneway() throws Exception {
		CableWire wireAB = new CableWire("A: Kevin's house", "B: LA Fitness", 4);
		CableWire wireAC = new CableWire("A: Kevin's house", "C: Movie theater", 3);
		CableWire wireCB = new CableWire("C: Movie theater", "B: LA Fitness", 2);
		CableWire wireCD = new CableWire("C: Movie theater", "D: Secret hideout", 1);


		Set<CableWire> edges = new HashSet<CableWire>();
		edges.add(wireAB);
		edges.add(wireAC);
		edges.add(wireCB);
		edges.add(wireCD);

		Set<CableWire> minBacon = BaconCableCompany.getMst(edges);
		assertTrue("square MST should contain edge 2", 
				minBacon.contains(wireCB));
		assertTrue("square MST should contain edge 1", 
				minBacon.contains(wireCD));
		assertTrue("square MST should contain edge 3", 
				minBacon.contains(wireAC));
		assertTrue("square MST should not contain edge 4",
				!minBacon.contains(wireAB));
		List<CableWire> path = BaconCableCompany.pathUsingMst(edges, "A: Kevin's house", "D: Secret hideout");
		assertEquals("squareMST path A->D length", 2, path.size());
		assertEquals("squareMST path A->D segment 0", wireAC, path.get(0));
		assertEquals("squareMST path A->D segment 1", wireCD, path.get(1));
	}

	@Test
	public void squarePath() throws Exception {
		//this code was duplicated for test modularity and so that
		//the asserts have access to the wireXX variables
		CableWire wireAB = new CableWire("A: Kevin's house", "B: LA Fitness", 1);
		CableWire wireBA = new CableWire("B: LA Fitness", "A: Kevin's house", 1);
		CableWire wireAC = new CableWire("A: Kevin's house", "C: Movie theater", 4);
		CableWire wireCA = new CableWire("C: Movie theater", "A: Kevin's house", 4);
		CableWire wireCB = new CableWire("C: Movie theater", "B: LA Fitness", 5);
		CableWire wireBC = new CableWire("B: LA Fitness", "C: Movie theater", 5);
		CableWire wireCD = new CableWire("C: Movie theater", "D: Secret hideout", 3);
		CableWire wireDC = new CableWire("D: Secret hideout", "C: Movie theater", 3);

		Set<CableWire> edges = new HashSet<CableWire>();
		edges.add(wireAB);
		edges.add(wireBA);
		edges.add(wireAC);
		edges.add(wireCA);
		edges.add(wireCB);
		edges.add(wireBC);
		edges.add(wireCD);
		edges.add(wireDC);

		List<CableWire> path = BaconCableCompany.pathUsingMst(edges, "A: Kevin's house", "D: Secret hideout");
		assertEquals("squareMST path A->D length", 2, path.size());
		assertEquals("squareMST path A->D segment 0", wireAC, path.get(0));
		assertEquals("squareMST path A->D segment 1", wireCD, path.get(1));
	}
	
	
	@Test 
	public void testStrangePath() throws Exception {
		CableWire wireAB = new CableWire("A: Kevin's house", "B: LA Fitness", 1);
		CableWire wireBA = new CableWire("B: LA Fitness", "A: Kevin's house", 1);
		CableWire wireCD = new CableWire("C: Movie theater", "D: Secret hideout", 3);

		Set<CableWire> edges = new HashSet<CableWire>();
		edges.add(wireAB);
		edges.add(wireBA);
		edges.add(wireCD);

		List<CableWire> path = BaconCableCompany.pathUsingMst(edges, "B: LA Fitness", "D: Secret hideout");
		assertEquals("there is no path for this case", path, null);
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void emptyinput() throws Exception {
		
		CableWire wireAB = new CableWire("A: Kevin's house", "B: LA Fitness", 1);
		CableWire wireBA = new CableWire("B: LA Fitness", "A: Kevin's house", 1);
		
		Set<CableWire> edges = new HashSet<CableWire>();
		edges.add(wireAB);
		edges.add(wireBA);
		
		BaconCableCompany.pathUsingMst(edges, "B: LA Fitness", "D: Secret hideout");
	}
}
